package lumis.service.report;

import java.util.ArrayList;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;

import lumis.doui.processaction.ProcessActionHandler;
import lumis.doui.source.Source;
import lumis.doui.source.field.ISourceField;
import lumis.portal.PortalException;
import lumis.portal.PortalObjectNotFoundException;
import lumis.portal.manager.ManagerFactory;
import lumis.portal.manager.ManagerFactoryInternal;
import lumis.portal.report.IReportManager;
import lumis.portal.report.Report;
import lumis.portal.report.ReportParameter;
import lumis.portal.report.ReportType;
import lumis.portal.report.ReportTypeParameter;
import lumis.util.XmlUtil;

/**
* Process Action Handler responsible for processing report administration actions.
* 
* @version $Revision: 12710 $ $Date: 2011-03-18 17:00:16 -0300 (Fri, 18 Mar 2011) $
 * @since 4.1.0
*/
public class ReportProcessActionHandler extends ProcessActionHandler<Source<?>>
{
	public void processAction() throws PortalException
	{
		String actionType = XmlUtil.readAttributeString("actionType", processActionNode);

		if(actionType.equals("addReport"))
			addReport();
		if(actionType.equals("updateReport"))
			updateReport();
		else if (actionType.equals("deleteReport"))
			deleteReport();
	}

	/**
	 * Returns a reporting, if it also belongs to this process action handler's
	 * source service instance.
	 * @param reportId the report identifier.
	 * @return the report.
	 * @since 4.2.1
	 */
	private Report getReport(String reportId) throws PortalException
	{
		String serviceInstanceId = source.getSourceContext().getServiceInstanceConfig().getId();
		try
		{
			return (Report)ManagerFactory.getEntityManager().createQuery(
					"select rsi.report from ReportServiceInstance rsi " +
					"where rsi.report.id = :reportId and " +
					"rsi.serviceInstanceId = :serviceInstanceId")
					.setParameter("reportId", reportId)
					.setParameter("serviceInstanceId", serviceInstanceId)
					.getSingleResult();
		}
		catch(NoResultException e)
		{
			throw new PortalObjectNotFoundException("Report with id='" + reportId + 
					"' in service instance '"+ serviceInstanceId + "'");
		}
	}

	public void addReport() throws PortalException
	{
		// get reportType
		IReportManager reportManager = ManagerFactoryInternal.getReportManager();
		String reportTypeId = getParameter("reportTypeId", String.class);
		ReportType reportType = reportManager.getReportType(reportTypeId);

		// create report
		Report report = new Report();
		report.setName(getParameter("name", String.class));
		report.setDescription(getParameter("description", String.class));
		report.setReportType(reportType);
		
		// add report parameters
		addReportParameters(report);

		// persist report
		EntityManager entityManager = ManagerFactory.getEntityManager();
		entityManager.persist(report);
		
		// persist report-serviceInstance relationship
		ReportServiceInstance reportServiceInstance = new ReportServiceInstance();
		reportServiceInstance.setServiceInstanceId(source.getSourceContext().getServiceInstanceConfig().getId());
		reportServiceInstance.setReport(report);
		entityManager.persist(reportServiceInstance);
		
		addDefaultResponse();
	}

	/**
	 * Adds parameters in a report according to its reportType and parameters
	 * in this process action handler.
	 * @param report the report.
	 * @since 4.2.0
	 */
	private void addReportParameters(Report report) throws PortalException
	{
		for (ReportTypeParameter reportTypeParameter: report.getReportType().getParameters())
		{
			String parameterName = reportTypeParameter.getName();
			
			// calculate value
			String value;
			ISourceField field = source.getField(parameterName);
			if(field != null)
				value = field.getConverter().convert(String.class, getParameter(parameterName), field.getDataType().getDefinitionLocale(), field.getDataType().getDefinitionPattern());
			else
				value = getParameter(parameterName, String.class);
			
			// add parameter to report if a value exists
			if (value != null)
			{
				ReportParameter reportParameter = report.addParameter();
				reportParameter.setName(parameterName);
				reportParameter.setValue(value);
			}
		}
	}
	
	public void updateReport() throws PortalException
	{
		// get reportType
		IReportManager reportManager = ManagerFactoryInternal.getReportManager();
		String reportTypeId = getParameter("reportTypeId", String.class);
		ReportType reportType = reportManager.getReportType(reportTypeId);

		// get report 
		Report report = getReport(getParameter("id", String.class));
		
		// update properties
		report.setName(getParameter("name", String.class));
		report.setDescription(getParameter("description", String.class));
		report.setReportType(reportType);

		// remove pre-existing report parameters
		for (ReportParameter reportParameter: new ArrayList<ReportParameter>(report.getParameters()))
			reportParameter.delete();
		ManagerFactory.getEntityManager().flush();

		// add report parameters
		addReportParameters(report);
		
		addDefaultResponse();
	}
	
	public void deleteReport() throws PortalException
	{
		EntityManager entityManager = ManagerFactory.getEntityManager();

		String[] reportIds = (String[]) getParameter("id");
		for (String reportId : reportIds)
		{
			Report report = getReport(reportId);
			entityManager.remove(report);
		}

		addDefaultResponse();
	}
}
